package db

import (
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"sync"
)

// 文件名常量
const (
	HintFilename  = "LunovaDB.hint"
	FileName      = "LunovaDB%d.db"
	MergeFileName = "LunovaDB%d_m.db"
)

type DBFile struct {
	File          *os.File
	Offset        int64
	HeaderBufPool *sync.Pool
	Id            uint32
}

func NewHintFile(path string) (*DBFile, error) {
	fileName := filepath.Join(path, HintFilename)
	return newInternal(fileName, hintentryHeaderSize)
}

func NewDBFile(path, dbFileName string) (*DBFile, error) {
	fileName := filepath.Join(path, dbFileName)
	return newInternal(fileName, entryHeaderSize)
}

// NewMergeDBFile 新建一个合并时的数据文件
func NewMergeDBFile(path string) (*DBFile, error) {
	fileName := filepath.Join(path, MergeFileName)
	return newInternal(fileName, entryHeaderSize)
}

func newInternal(fileName string, poolSize int) (*DBFile, error) {
	var id int
	file, err := os.OpenFile(fileName, os.O_CREATE|os.O_RDWR, 0644)
	if err != nil {
		return nil, err
	}

	stat, err := os.Stat(fileName)
	if err != nil {
		return nil, err
	}
	pool := &sync.Pool{New: func() interface{} {
		return make([]byte, poolSize)
	}}
	re := regexp.MustCompile(`LunovaDB(\d+)\.db`)
	matches := re.FindStringSubmatch(fileName)
	if len(matches) > 1 {
		id, err = strconv.Atoi(matches[1])
		if err != nil {
			return nil, err
		}
		if id > int(maxFileId) {
			maxFileId = uint32(id)
		}
	} else {
		id = 0
	}
	// fmt.Println("filename", fileName)
	// fmt.Println("statSize", stat.Size())
	return &DBFile{Offset: stat.Size(), File: file, HeaderBufPool: pool, Id: uint32(id)}, nil
}

// HintRead 从 offset 处开始读取
func (df *DBFile) HintRead(offset int64) (e *HintEntry, err error) {
	buf := df.HeaderBufPool.Get().([]byte)
	defer df.HeaderBufPool.Put(buf)
	if _, err = df.File.ReadAt(buf, offset); err != nil {
		return
	}
	if e, err = HintDecode(buf); err != nil {
		return
	}

	offset += hintentryHeaderSize
	if e.KeySize > 0 {
		//读取 key
		key := make([]byte, e.KeySize)
		if _, err = df.File.ReadAt(key, offset); err != nil {
			return
		}
		e.Key = key
	}
	return
}

// Read 从 offset 处开始读取
func (df *DBFile) Read(offset int64) (e *Entry, err error) {
	buf := df.HeaderBufPool.Get().([]byte)
	defer df.HeaderBufPool.Put(buf)
	if _, err = df.File.ReadAt(buf, offset); err != nil {
		return
	}
	if e, err = Decode(buf); err != nil {
		return
	}

	offset += entryHeaderSize
	if e.KeySize > 0 {
		//读取 key
		key := make([]byte, e.KeySize)
		if _, err = df.File.ReadAt(key, offset); err != nil {
			return
		}
		e.Key = key
	}

	offset += int64(e.KeySize)
	if e.ValueSize > 0 {
		//读取 value
		value := make([]byte, e.ValueSize)
		if _, err = df.File.ReadAt(value, offset); err != nil {
			return
		}
		e.Value = value
	}
	return
}

func (df *DBFile) Write(e *Entry) (err error) {
	enc, err := e.Encode()
	if err != nil {
		return err
	}
	_, err = df.File.WriteAt(enc, df.Offset)
	df.Offset += e.GetSize()
	return
}

func (df *DBFile) HintWrite(e *HintEntry) (err error) {
	enc, err := e.HintEncode()
	if err != nil {
		return err
	}
	_, err = df.File.WriteAt(enc, df.Offset)
	df.Offset += e.GetSize()
	return
}
